package org.distributed.transaction.core.executor;

import org.distributed.transaction.core.annotion.PropagationStatus;
import org.distributed.transaction.core.context.TransactionContext;
import org.distributed.transaction.core.context.TransactionProcessorContext;
import org.distributed.transaction.core.enums.DTTransactionType;
import org.distributed.transaction.core.enums.Propagation;
import org.distributed.transaction.core.exception.TransactionException;
import org.distributed.transaction.core.process.TransactionProcessor;
import org.distributed.transaction.core.propagation.PropagationResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 分布式事务执行器
 * 
 * @author chenfanglin
 *
 */
@Component
public class TransactionExecutor {

	private static final Logger logger = LoggerFactory.getLogger(TransactionExecutor.class);

	@Autowired
	private PropagationResolver propagationResolver;

	@Autowired
	private TransactionProcessorContext transactionProcessorContext;

	/**
	 * 执行分布式事务
	 * 
	 * @param transactionContext
	 * @return
	 * @throws Throwable 
	 */
	public Object execute(TransactionContext transactionContext) throws Throwable {
		DTTransactionType dtTransactionType = transactionContext.getDtTransactionType();
		/**
		 * 根据事务传播机制判断 加入事务组还是创建事务组
		 */
		Propagation propagation = transactionContext.getPropagation();

		PropagationStatus propagationStatus = propagationResolver.resolvePropagation(propagation);
		// 获取事务处理器
		TransactionProcessor transactionProcessor = transactionProcessorContext
				.getTransactionProcessor(dtTransactionType, propagationStatus);

		try {
			// 1、业务执行前
			transactionProcessor.preBusinessCode(transactionContext);
			logger.info("execute preBusinessCode success,groupId={},dtTransactionType={}",
					transactionContext.getGroupId(), dtTransactionType);
			// 2、执行业务
			Object result = transactionProcessor.doBusinessCode(transactionContext);
			logger.info("execute doBusinessCode success,groupId={}", transactionContext.getGroupId());
			// 3、执行业务成功
			transactionProcessor.onBusinessCodeSuccess(transactionContext, result);
			return result;
		} catch (TransactionException e) {
			logger.info("execute preBusinessCode or onBusinessCodeSuccess fail,groupId={}",transactionContext.getGroupId());
			throw e;
		} catch (Throwable e) {
			// 4、业务执行失败
			transactionProcessor.onBusinessCodeError(transactionContext, e);
		} finally {
			/**
			 * 回收资源
			 */
			transactionProcessor.clear(transactionContext);
		}
		return null;
	}

}
